home *** CD-ROM | disk | FTP | other *** search
- ///-*-C++-*-//////////////////////////////////////////////////////////////////
- //
- // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
- // for Shared-Memory Multiprocessors
- // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
- //
- // Copyright (c) 1998-2000, The University of Texas at Austin.
- //
- // This library is free software; you can redistribute it and/or modify
- // it under the terms of the GNU Library General Public License as
- // published by the Free Software Foundation, http://www.fsf.org.
- //
- // This library is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- //////////////////////////////////////////////////////////////////////////////
-
- #include <string.h>
- #include <stdio.h>
-
- #include "config.h"
-
- #if USE_PRIVATE_HEAPS
- #include "privateheap.h"
- #define HEAPTYPE privateHeap
- #else
- #define HEAPTYPE threadHeap
- #include "threadheap.h"
- #endif
-
- #include "processheap.h"
-
-
- processHeap::processHeap (void)
- : _buffer (NULL),
- _bufferCount (0)
- #if HEAP_FRAG_STATS
- , _currentAllocated (0),
- _currentRequested (0),
- _maxAllocated (0),
- _inUseAtMaxAllocated (0),
- _maxRequested (0)
- #endif
- {
- int i;
- // The process heap is heap 0.
- setIndex (0);
- for (i = 0; i < MAX_HEAPS; i++) {
- // Set every thread's process heap to this one.
- theap[i].setpHeap (this);
- // Set every thread heap's index.
- theap[i].setIndex (i + 1);
- }
- #if HEAP_LOG
- for (i = 0; i < MAX_HEAPS + 1; i++) {
- char fname[255];
- sprintf (fname, "log%d", i);
- unlink (fname);
- _log[i].open (fname);
- }
- #endif
- #if HEAP_FRAG_STATS
- hoardLockInit (_statsLock);
- #endif
- hoardLockInit (_bufferLock);
- }
-
-
- // Print out statistics information.
- void processHeap::stats (void) {
- #if HEAP_STATS
- int umax = 0;
- int amax = 0;
- for (int j = 0; j < MAX_HEAPS; j++) {
- for (int i = 0; i < SIZE_CLASSES; i++) {
- amax += theap[j].maxAllocated(i) * sizeFromClass (i);
- umax += theap[j].maxInUse(i) * sizeFromClass (i);
- }
- }
- printf ("Amax <= %d, Umax <= %d\n", amax, umax);
- #if HEAP_FRAG_STATS
- amax = getMaxAllocated();
- umax = getMaxRequested();
- printf ("Maximum allocated = %d\nMaximum in use = %d\nIn use at max allocated = %d\n", amax, umax, getInUseAtMaxAllocated());
- printf ("Still in use = %d\n", _currentRequested);
- printf ("Fragmentation (3) = %f\n", (float) amax / (float) getInUseAtMaxAllocated());
- printf ("Fragmentation (4) = %f\n", (float) amax / (float) umax);
- #endif
-
- #endif // HEAP_STATS
- #if HEAP_LOG
- printf ("closing logs.\n");
- fflush (stdout);
- for (int i = 0; i < MAX_HEAPS + 1; i++) {
- _log[i].close();
- }
- #endif
- }
-
-
-
- #if HEAP_FRAG_STATS
- void processHeap::setAllocated (int requestedSize,
- int actualSize)
- {
- hoardLock (_statsLock);
- _currentRequested += requestedSize;
- _currentAllocated += actualSize;
- if (_currentRequested > _maxRequested) {
- _maxRequested = _currentRequested;
- }
- if (_currentAllocated > _maxAllocated) {
- _maxAllocated = _currentAllocated;
- _inUseAtMaxAllocated = _currentRequested;
- }
- hoardUnlock (_statsLock);
- }
-
-
- void processHeap::setDeallocated (int requestedSize,
- int actualSize)
- {
- hoardLock (_statsLock);
- _currentRequested -= requestedSize;
- _currentAllocated -= actualSize;
- hoardUnlock (_statsLock);
- }
- #endif
-
-
- // free (ptr, pheap):
- // inputs: a pointer to an object allocated by malloc().
- // side effects: returns the block to the object's superblock;
- // updates the thread heap's statistics;
- // may release the superblock to the process heap.
-
- void processHeap::free (void * ptr)
- {
-
- // Return if ptr is 0.
- // This is the behavior prescribed by the standard.
- if (ptr == 0) {
- return;
- }
-
- // Find the block and superblock corresponding to this ptr.
-
- block * b = (block *) ptr - 1;
- assert (b->isValid());
-
- // Check to see if this block came from a memalign() call.
- if (((unsigned long) b->getNext() & 1) == 1) {
- // It did. Set the block to the actual block header.
- b = (block *) ((unsigned long) b->getNext() & ~1);
- assert (b->isValid());
- }
-
- b->markFree();
-
- superblock * sb = b->getSuperblock();
- assert (sb);
- assert (sb->isValid());
-
- const int sizeclass = sb->getBlockSizeClass();
-
- //
- // Return the block to the superblock,
- // find the heap that owns this superblock
- // and update its statistics.
- //
-
- hoardHeap * owner;
-
- // By acquiring the up lock on the superblock,
- // we prevent it from moving to the global heap.
- // This eventually pins it down in one heap,
- // so this loop is guaranteed to terminate.
- // (It should generally take no more than two iterations.)
- sb->upLock();
- while (1) {
- owner = sb->getOwner();
- owner->lock();
- if (owner == sb->getOwner()) {
- break;
- } else {
- owner->unlock();
- }
- // Suspend to allow ownership to quiesce.
- hoardYield();
- }
-
- #if HEAP_LOG
- MemoryRequest m;
- m.free (ptr);
- getLog (owner->getIndex()).append(m);
- #endif
- #if HEAP_FRAG_STATS
- setDeallocated (b->getRequestedSize(), 0);
- #endif
-
- int sbUnmapped = owner->freeBlock (b, sb, sizeclass, this);
-
- owner->unlock();
- if (!sbUnmapped) {
- sb->upUnlock();
- }
- }
-